package concurrent;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * 原子类
 *
 * @author jack.wu
 * @since 2019/12/31 17:23
 */
public class AtomicDemo {

}

/**
 * ABA问题
 */
class AtomicDemo1 {
    private static int accountMoney = 19;
    static AtomicReference<Integer> money = new AtomicReference<>(accountMoney);

    /**
     * 模拟充值
     */
    static void recharge() {
        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                for (int j = 0; j < 3; j++) {
                    Integer moneyValue = AtomicDemo1.money.get();
                    if (moneyValue == accountMoney) {
                        if (money.compareAndSet(moneyValue, moneyValue + 20)) {
                            System.out.println("当前余额：" + moneyValue + "，小于20，充值20元成功，余额：" + money.get() + "元");
                        }
                    }
                    try {
                        TimeUnit.MILLISECONDS.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }

    /**
     * 模拟消费
     */
    static void consume() throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            Integer moneyValue = money.get();
            if (moneyValue > 20) {
                if (money.compareAndSet(moneyValue, moneyValue - 20)) {
                    System.out.println("当前余额：" + moneyValue + "，大于20，成功消费20元，余额：" + money.get() + "元");
                }
            }
            TimeUnit.MILLISECONDS.sleep(50);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        recharge();
        consume();
    }
}

/**
 * AtomicStampedRerence 他内部不仅维护了对象的值，还维护了一个时间戳
 * 当AtomicStampedRerence设置对象值时，对象值及时间戳都必须满足期望值，写入才会成功。
 * 因此，即使对象值被反复读写，写回原值，只要时间戳发生变量，就能防止不恰当的写入。
 */
class AtomicStampedReferenceDemo {

}
